<?php

/**
 * Model che rappresenta un agente nel DB.
 */
class Articolo extends StdModel
{

	private static $singleton = NULL;

	/**
	 * Ritorna una istanza globale di questo model.
	 * @return mixed La istanza globale.
	 */
	public static function getInstance()
	{
		if(self::$singleton == NULL)
			self::$singleton = new Articolo();
		return self::$singleton;
	}

	/*
	 * Specifiche attributi del tipo del Model rappresentato da questa classe
	 */
	public $attribTableName = "Articolo";
	public $attribLabel = "DescrizioneBreve";
	public $attribNames = array(STD_ID, "idAziendaRappresentata", "Tipo", "DescrizioneBreve", "UM", "Nome");
	public $attribExcludeFromAdd = array(STD_ID);
	public $attribExcludeFromEdit = array(STD_ID);
	public $attribLongNames = array(STD_ID => "ID", "idAziendaRappresentata" => "Produttore", "Tipo" => "Tipo",
		"DescrizioneBreve" => "Descrizione dell'articolo", "UM" => "Unit&agrave; di misura", "Nome" => "Nome");
	public $attribIsImportant = array(STD_ID => 2, "idAziendaRappresentata" => 1, "Tipo" => 1,
		"DescrizioneBreve" => 1, "UM" => 1, "Nome" => 1);
	public $attribIsNumeric = array(STD_ID => true, "idAziendaRappresentata" => true, "Tipo" => false,
		"DescrizioneBreve" => false, "UM" => false, "Nome" => false);
	public $attribIsForeignKey = array(STD_ID => false, "idAziendaRappresentata" => "Aziende Rappresentate",
		"Tipo" => false, "DescrizioneBreve" => false, "UM" => false, "Nome" => false);

	const joinTable = "Articolo LEFT JOIN AziendaRappresentata ON Articolo.idAziendaRappresentata = AziendaRappresentata.ID";
	const joinSelect ="Articolo.*, AziendaRappresentata.Ragsoc, AziendaRappresentata.Indirizzo, AziendaRappresentata.CAP, AziendaRappresentata.Citta, AziendaRappresentata.Provincia, AziendaRappresentata.Stato";

	/*
	 * Specifiche per gli elementi form associati agli attributi
	 */
	private static $attribHTMLFormValue = array(STD_ID => FORM_HIDDEN, "idAziendaRappresentata" => FORM_EXTERNAL_SELECTOR,
		"Tipo" => FORM_TEXT, "DescrizioneBreve" => FORM_TEXT_LONG, "UM" => FORM_TEXT, "Nome" => FORM_TEXT);
	private static $attribHTMLFormIsMandatory = array(STD_ID => true, "idAziendaRappresentata" => false,
		"Tipo" => false, "DescrizioneBreve" => true, "UM" => true, "Nome" => false);

	/**
	 * Restituisce l'HTML per creare un campo di un form adatto a contenere il
	 * valore dell'attribbuto passato. Questo campo di testo sarà vuoto e dovrà
	 * servire per la creazione di una nuova istanza in DB di questo model.
	 * @param string $attribName Nome dell'attributo su cui creare il campo.
	 * @return string Stringa contenente l'HTML dell'elemento creato.
	 */
	public function getAddFormCodeFromAttribute($db,$attribName)
	{
		if(!isset(self::$attribHTMLFormValue[$attribName]) || $attribName == STD_ID)
			return "";
		$dataliststr = "";
		if($attribName == "Tipo" || $attribName == "UM")
		{
			$datalist = $db->getDistinctValuesFromTableField($this->attribTableName, $attribName);
			if($datalist)
				$dataliststr = ModelUtils::getDatalistForTextFormElement ($attribName, $datalist);
		}
		switch(self::$attribHTMLFormValue[$attribName])
		{
			case FORM_TEXT: return (ModelUtils::getTextFormElement($attribName, "", self::$attribHTMLFormIsMandatory[$attribName]).$dataliststr);
			case FORM_TEXT_LONG: return ModelUtils::getLongTextFormElement($attribName, "", NULL, NULL, self::$attribHTMLFormIsMandatory[$attribName]);
			case FORM_EXTERNAL_SELECTOR: return ModelUtils::getExternalSelectorFormElement($attribName, "externalSelector.php", "AziendaRappresentata", "", "", self::$attribHTMLFormIsMandatory[$attribName]);
			default: return "";
		}	
	}

	/**
	 * Restituisce l'HTML per creare un campo di testo adatto a contenere il
	 * valore dell'attribbuto passato. Questo campo di testo conterrà il valore
	 * attualmente assunto da questo attributo in questa tupla.
	 * @param DatabaseManager $db Database su cui effettuare una possibile
	 * interrogazione.
	 * @param string $attribName Nome dell'attributo di cui creare il codice.
	 * @return string Il codice HTML dell'elemento form corrispondente.
	 */
	public function getEditFormCodeFromAttribute($db, $attribName)
	{
		$dataliststr = "";
		if($attribName == "Tipo" || $attribName == "UM")
		{
			$datalist = $db->getDistinctValuesFromTableField($this->attribTableName, $attribName);
			if($datalist)
				$dataliststr = ModelUtils::getDatalistForTextFormElement ($attribName, $datalist);
		}
		switch(self::$attribHTMLFormValue[$attribName])
		{
			case FORM_HIDDEN: return ModelUtils::getHiddenFormElement($attribName, $this->dataTupla[$attribName], self::$attribHTMLFormIsMandatory[$attribName]);
			case FORM_TEXT: return (ModelUtils::getTextFormElement($attribName, $this->dataTupla[$attribName], self::$attribHTMLFormIsMandatory[$attribName]).$dataliststr);
			case FORM_TEXT_LONG: return ModelUtils::getLongTextFormElement($attribName, $this->dataTupla[$attribName], NULL, NULL, self::$attribHTMLFormIsMandatory[$attribName]);
			case FORM_EXTERNAL_SELECTOR: {
				return ($this->getAziendaRappresentata($db) == NULL) ?
						$this->getAddFormCodeFromAttribute ($db, $attribName) :
						ModelUtils::getExternalSelectorFormElement($attribName, "externalSelector.php", "AziendaRappresentata", $this->dataTupla[$attribName], $this->getAziendaRappresentata($db)->getLabel(), self::$attribHTMLFormIsMandatory[$attribName]);
			}
			default: return "";
		}
	}

	/**
	 * Costruttore che acquisisce l'array dei valori associativi.
	 * @param type $data L'array associativo a cui inizializzare questa istanza.
	 */
	public function __construct($data = NULL)
	{
		parent::__construct($data);
	}

	/**
	 * Crea una nuova istanza della sottoclasse specializzante.
	 * @param array $data I dati passati da cui recuperare i valori.
	 * @return mixed Una nuova instanza della sottoclasse specializzante.
	 */
	public function createNew($data)
	{
		$res = new Articolo($data);
		//se l'array contiene già le informazioni sull'azienda lo si crea direttamente anch'esso
		if(isset($data["Ragsoc"]))
		{
			$aziendaData = array();
			$aziendaData[STD_ID] = $data["idAziendaRappresentata"];
			$aziendaData["Ragsoc"] = $data["Ragsoc"];
			$res->chachedAzienda = AziendaRappresentata::getInstance()->createNew($aziendaData);
		}
		return $res;
	}
	
	/**
	 * Duplica i valori di una tupla, nel DB.
	 * Eventuali sottoclassi potrebbero implementare questo metodo per duplicare
	 * anche le associazioni NxN con un altra tabella.
	 * @param DatabaseManager $db Database su cui effettuare l'INSERT.
	 * @return mixed Restituisce l'istanza corrispondete alla nuova tupla se
	 * l'INSERT è andato a buon fine, NULL altrimenti.
	 */
	public function duplicateInDB($db)
	{
		$oldid = $this->dataTupla[STD_ID];
		$newInst = parent::duplicateInDB($db);
		VariazioneArticolo::getInstance()->duplicateFromIDArticolo($db,$oldid,$newInst->dataTupla[STD_ID]);
		return $newInst;
	}

	/**
	 * Metodo che restituisce una etichetta che rappresenta il valore di un
	 * attributo: nella sua versione di default ritorna esattamente il valore
	 * associato a quell'attributo, ma è possibile implementarlo nelle
	 * sottoclassi per specificare opportuni comportamenti, come ad esempio di
	 * non far stampare un numero che rappresenta una chiave esterna, ma invece
	 * una etichetta della tupla ad essa associata.
	 * @param DatabaseManager $db Database su cui poter effettuare una possibile
	 * interrogazione.
	 * @param string $attrib Attributo di cui stampare l'etichetta del valore.
	 * @return string Il valore associato all'attributo o NULL se l'attributo
	 * non è stato trovato.
	 */
	public function getDataLabel($db, $attrib)
	{
		if($attrib == "idAziendaRappresentata")
		{
			$az = $this->getAziendaRappresentata($db);
			return $az == NULL ? "" : $az->getLabel();
		}
		return parent::getDataLabel($db, $attrib);
	}

	private $chachedAzienda = NULL;

	/**
	 * Ritorna una istanza di AziendaRappresentata corrispondente alla chiave
	 * esterna "idAziendaRappresentata" di questa tupla.
	 * @param DatabaseManager $db Database da interrogare.
	 * @return AziendaRappresentata L'instanza creata o NULL in caso di errore.
	 */
	public function getAziendaRappresentata($db)
	{
		$idag = isset($this->dataTupla["idAziendaRappresentata"]) ? $this->dataTupla["idAziendaRappresentata"] : NULL;
		if($idag != NULL && $idag > 0)
		{
			if($this->chachedAzienda == NULL || $this->chachedAzienda->dataTupla[STD_ID] != $idag)
			{
				$this->chachedAzienda = AziendaRappresentata::getInstance()->getFromDB($db, $this->dataTupla["idAziendaRappresentata"]);
				return $this->chachedAzienda;
			}
			else
				return $this->chachedAzienda;
		}
		return NULL;
	}

	/**
	 * Carica dal DB una lista di istanze di questa sottoclasse caricate con i
	 * valori delle tuple trovate secondo le specifiche passate.
	 * @param DatabaseManager $db Database da cui prelevare le tuple.
	 * @param int $limitMin Limite basso da cui iniziare a prelevare tuple, o
	 * NULL per non usare i limiti.
	 * @param int $limitMax Limite alto a cui fermarsi di prelevare tuple, o
	 * NULL per non usare i limiti.
	 * @param string $orderBy Ordinamento con cui prelevare le tuple, o "" per
	 * non usare alcun ordinamento.
	 * @return array L'array delle nuove istanze create a partire dai valori
	 * trovati nel DB o NULL nel caso qualcosa sia andato storto.
	 */
	public function getListFromDB($db, $limitMin, $limitMax, $orderBy, $cond = "")
	{
		$limits = ($limitMin === NULL || $limitMax === NULL ? "" : ($limitMin.", ".($limitMax-$limitMin)) );
		//SELECT Articolo.*, AziendaRappresentata.Ragsoc, AziendaRappresentata.Indirizzo, AziendaRappresentata.CAP, AziendaRappresentata.Citta, AziendaRappresentata.Provincia, AziendaRappresentata.Stato FROM Articolo LEFT JOIN AziendaRappresentata ON Articolo.idAziendaRappresentata = AziendaRappresentata.ID
		$rs = $db->EnumerateTableStartExt(self::joinSelect, self::joinTable, $orderBy,$cond,$limits);
		if($rs == FALSE)
			return NULL;
		$retarr = array();
		while($db->EnumerateTableNext($rs))
			$retarr[] = $this->createNew($db->EnumerateTableGetValues($rs));
		return $retarr;
	}

	/**
	 * Cerca una serie di tuple nel DB e ritorna tante istanze della sottoclasse
	 * specializzante, quante sono le rispettive tuple trovate con i rispettivi
	 * valori caricati entro i limiti specificati.
	 * @param DatabaseManager $db Database da cui prelevare le tuple.
	 * @param string $paramName Nome dell'attributo su cui effettuare la
	 * ricerca.
	 * @param string $paramValue Valore che l'attributo deve assumere per
	 * includere la sua rispettiva tupla.
	 * @param int $limitMin Limite basso da cui iniziare a prelevare tuple, o
	 * NULL per non usare i limiti.
	 * @param int $limitMax Limite alto a cui fermarsi di prelevare tuple, o
	 * NULL per non usare i limiti.
	 * @param string $orderBy Ordinamento con cui prelevare le tuple, o "" per
	 * non usare alcun ordinamento.
	 * @return array L'array delle nuove istanze create a partire dai valori
	 * trovati nel DB o NULL nel caso qualcosa sia andato storto.
	 */
	public function searchByParam($db, $paramName, $paramValue, $limitMin, $limitMax, $orderBy)
	{
		if(!isset($this->attribIsNumeric[$paramName]))
			return NULL;
		$limits = ($limitMin === NULL || $limitMax === NULL ? "" : ($limitMin.", ".($limitMax-$limitMin)) );
		$cond = NULL;
		if($paramName == "idAziendaRappresentata")
		{
			//se il parametro della ricerca è idAziendaRappresentata, allora la ricerca si effettua sulla ragione sociale dell'azienda
			$cond = "Ragsoc LIKE '%".ModelUtils::escape_sq_for_SQL($paramValue)."%'";
		}
		else
		{
			//caso contrario si effettua sul parametro specificato come di norma
			$paramIsNumeric = $this->attribIsNumeric[$paramName];
			if($paramName == STD_ID)
				$paramName = $this->attribTableName.".".STD_ID;
			$cond = ($paramIsNumeric ? $paramName." = ".$paramValue : $paramName." LIKE '%".ModelUtils::escape_sq_for_SQL($paramValue)."%'");
		}
		$rs = $db->EnumerateTableStartExt(self::joinSelect, self::joinTable, $orderBy, $cond, $limits );
		if($rs == FALSE)
			return NULL;
		$retarr = array();
		while($db->EnumerateTableNext($rs))
			$retarr[] = $this->createNew($db->EnumerateTableGetValues($rs));
		return $retarr;
	}

	/**
	 * Restituiscce il numero di tuple del risultato della ricerca.
	 * @param DatabaseManager $db Database da interrogare.
	 * @param string $searchAttrib Nome dell'attributo su cui effettuare la
	 * ricerca.
	 * @param string $searchVal Valore che l'attributo deve assumere per far
	 * contare la propria tupla.
	 * @return int Restituisce il numero di tuple trovate o FALSE in caso di
	 * errore.
	 */
	public function getRecordsNumOfSearchResult($db,$searchAttrib,$searchVal)
	{
		if(!isset($this->attribIsNumeric[$searchAttrib]))
			return FALSE;
		$cond = NULL;
		if($searchAttrib == "idAziendaRappresentata")
		{
			//se il parametro della ricerca è idAziendaRappresentata, allora la ricerca si effettua sulla ragione sociale dell'azienda
			$cond = "Ragsoc LIKE '%".ModelUtils::escape_sq_for_SQL($searchVal)."%'";
		}
		else
		{
			//caso contrario si effettua sul parametro specificato come di norma
			$paramIsNumeric = $this->attribIsNumeric[$searchAttrib];
			if($searchAttrib == STD_ID)
				$searchAttrib = $this->attribTableName.".".STD_ID;
			$cond = ($paramIsNumeric ? $searchAttrib." = ".$searchVal : $searchAttrib." LIKE '%".ModelUtils::escape_sq_for_SQL($searchVal)."%'");
		}
		return $db->GetRecordsNum(self::joinTable,$cond);
	}

}

?>
